package main

import (
	"fmt"
)

// 红中麻将胡牌算法

var shunziAllArry = make([][]int, 0)
var keziAllArry = make([][]int, 0)
var huCodeMap = make(map[int]map[string]struct{}) //string为9个数字，每个数字小于等于4

func genShunziAllArry() {
	for i := 1; i <= 9; i++ {
		shunziAllArry = append(shunziAllArry, []int{i, i, i})
	}
}

func genKeziAllArry() {
	for i := 1; i <= 7; i++ {
		keziAllArry = append(keziAllArry, []int{i, i + 1, i + 2})
		keziAllArry = append(keziAllArry, []int{i, i + 1, i + 2})
		keziAllArry = append(keziAllArry, []int{i, i + 1, i + 2})
		keziAllArry = append(keziAllArry, []int{i, i + 1, i + 2})
	}
}

func generateKey(cards []int) string {
	key := ""
	dic := []string{"0", "1", "2", "3", "4"}
	for _, v := range cards {
		key += dic[v]
	}
	return key
}

func checkCodeArr(codeArr []int) (check bool) {
	// [1,1,1,3,4,2,2,1,1...] 27个元素
	check = true
	for _, v := range codeArr {
		if v > 4 {
			check = false
			return
		}
	}
	return
}

func replaceAt(str string, index int, replacement string) string {
	prefix := str[:index]
	// 截取从指定位置之后的子串
	suffix := str[index+1:]
	// 返回替换后的字符串
	return prefix + replacement + suffix
}

// 获取单门牌所有的组合
func getAllCombinations() (codes [][]int) {
	allArr := append(keziAllArry, shunziAllArry...)

	data := make([][][]int, 0)
	data = append(data, search2(allArr, 1)...)
	data = append(data, search2(allArr, 2)...)
	data = append(data, search2(allArr, 3)...)
	data = append(data, search2(allArr, 4)...)
	// data: [[[1,2,3], [3,4,5],[6,6,6], [6,7,8]], [[2,3,4], [5,5,5]]...]
	for _, v := range data {
		// v: [[1,2,3], [3,4,5],[11,12,13], [23,23,23]]
		var codeArr = make([]int, 9)
		for _, vv := range v {
			codeArr[vv[0]-1] += 1
			codeArr[vv[1]-1] += 1
			codeArr[vv[2]-1] += 1
		}
		if checkCodeArr(codeArr) {
			codes = append(codes, codeArr)
		}
	}
	return
}

func checkTransferCode(codeList []int, idxList []int) (bool, []int) {
	var newCodeList = make([]int, len(codeList))
	for i, v := range codeList {
		newCodeList[i] = v
	}
	for _, idx := range idxList {
		if newCodeList[idx] <= 0 {
			return false, newCodeList
		} else {
			newCodeList[idx]--
		}
	}
	return true, newCodeList
}

func magic(codes [][]int, hongzhongCount int) (res [][]int) {
	indexArry := []int{}
	// indexArry: [1,2,3,4,5,6,7,8,9]
	for i := 0; i < 9; i++ {
		indexArry = append(indexArry, i)
	}
	indexCombines := search(indexArry, hongzhongCount)
	for _, codeList := range codes {
		for _, indexList := range indexCombines {
			valid, data := checkTransferCode(codeList, indexList)
			if valid {
				res = append(res, data)
			}
		}
	}
	return
}

type sourceCode struct {
	codes          []int
	hongzhongCount int
}

func dingjiang(sc sourceCode) (res map[int][][]int) {
	res = make(map[int][][]int) //27个长度
	res[0] = make([][]int, 0)
	res[1] = make([][]int, 0) // 保留1个红中
	res[2] = make([][]int, 0) // 保留2个红中
	res[3] = make([][]int, 0) // ...
	res[4] = make([][]int, 0)
	for i, v := range sc.codes {
		for j := 0; j <= 2; j++ {
			newSlice := append([]int{}, sc.codes...)
			// 拿j个红中做将
			if (v+j >= 2) && (sc.hongzhongCount-j >= 0) {
				newSlice[i] = v + j - 2
				// 拿剩余 sc.hongzhongCount-j 个红中做癞子
				res[sc.hongzhongCount-j] = append(res[sc.hongzhongCount-j], newSlice)
			}
		}
	}
	return res
}

func isHu(codes []int, hongzhongCount int) (result bool) {
	// codes长度为9
	key := generateKey(codes)
	if key == "000000000" {
		result = true
		return
	}
	if v, ok := huCodeMap[hongzhongCount]; ok {
		if _, exist := v[key]; exist {
			result = true
		}
	}
	return
}

func checkHu(sc sourceCode) (check bool) {
	if len(sc.codes) != 27 {
		fmt.Println("格式错误")
		return
	}
	// 定将
	res := dingjiang(sc)

	for count, codeIntList := range res {
		for _, v := range codeIntList {
			// 将codeIntList分成三份，分别判断
			if isHu(v[0:9], count) && isHu(v[9:18], count) && isHu(v[18:27], count) {
				check = true
				return
			}
		}

	}
	return
}

func slice2Map(slice [][]int) (res map[string]struct{}) {
	res = make(map[string]struct{})
	for _, v := range slice {
		key := generateKey(v)
		res[key] = struct{}{}
	}
	return
}

func main() {
	genShunziAllArry()
	genKeziAllArry()
	codes0 := getAllCombinations() // [[0 0 0 0 0 3 3 3 3]...]
	codes1 := magic(codes0, 1)
	codes2 := magic(codes0, 2)
	codes3 := magic(codes0, 3)
	codes4 := magic(codes0, 4)
	huCodeMap[0] = slice2Map(codes0)
	huCodeMap[1] = slice2Map(codes1)
	huCodeMap[2] = slice2Map(codes2)
	huCodeMap[3] = slice2Map(codes3)
	huCodeMap[4] = slice2Map(codes4)
	sc := sourceCode{
		codes:          []int{3, 3, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		hongzhongCount: 2,
	}
	fmt.Println(checkHu(sc))

}
